/**
 * Copyright (c) 2015-2017, Henry Yang 杨勇 (gismail@foxmail.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lambkit.generator.template.impl;

import com.lambkit.generator.template.TemplateEngine;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

import java.io.File;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

public class FreemarkerTemplateEngine extends TemplateEngine {

	@Override
	public String execute(String templateFolder, String templatePath, String templateType, Map<String, Object> templateModel) {
		String filePath = templatePath;
		String res = null;
		try {
			// Freemarker配置
			Configuration config = new Configuration();
			if("class".equalsIgnoreCase(templateType)) {
				templateFolder = templateFolder.startsWith("class:/") ? templateFolder.substring(6) : templateFolder;
				templateFolder = templateFolder.startsWith("//") ? templateFolder.substring(1) : templateFolder;
				// 设置模板加载器为当前类所在的包路径，并指定加载器加载JAR内部资源
				config.setClassForTemplateLoading(FreemarkerTemplateEngine.class, templateFolder);
			} else {
				// filepath:ftl存放路径（/template/file/static）
				String folderpath = getFolderPath(templateFolder);
				config.setDirectoryForTemplateLoading(new File(folderpath));
			}
			// 设置包装器，并将对象包装为数据模型
			config.setObjectWrapper(new DefaultObjectWrapper());
			//config.setDefaultEncoding("UTF-8");   //这个一定要设置，不然在生成的页面中 会乱码
			StringWriter fw = new StringWriter();
			// 获取模板,并设置编码方式，这个编码必须要与页面中的编码格式一致
			// 否则会出现乱码
			// templatePath:ftl文件名称（template.ftl）
			//String filename = getFileName(fileVMPath);
			Template template = config.getTemplate(filePath, "UTF-8");
			// 合并数据模型与模板
			template.process(templateModel, fw);
			res = fw.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//Printer.print(this, "generator"("--------Freemarker模板引擎处理完毕over!-----------");
		return res;
	}

	@Override
	public String execute(String templateContent, Map<String, Object> templateModel) {
		String res = null;
		try {
			String templateName = hashKey(templateContent);
			StringTemplateLoader stringLoader = new StringTemplateLoader();
			stringLoader.putTemplate(templateName, templateContent);

			// Freemarker配置
			Configuration config = new Configuration();
			// 设置包装器，并将对象包装为数据模型
			config.setObjectWrapper(new DefaultObjectWrapper());
			config.setTemplateLoader(stringLoader);
			//这个一定要设置，不然在生成的页面中 会乱码
			config.setDefaultEncoding("UTF-8");

			StringWriter fw = new StringWriter();
			// 获取模板,并设置编码方式，这个编码必须要与页面中的编码格式一致否则会出现乱码
			Template template = new Template(templateName, templateContent, config);
			// 合并数据模型与模板
			template.process(templateModel, fw);
			res = fw.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//Printer.print(this, "generator"("--------Freemarker模板引擎处理完毕over!-----------");
		return res;
	}

	/**
	 * A hashing method that changes a string (like a URL) into a hash suitable
	 * for using as a disk filename.
	 */
	private String hashKey(String key) {
		String cacheKey;
		try {
			final MessageDigest mDigest = MessageDigest.getInstance("MD5");
			mDigest.update(key.getBytes());
			cacheKey = bytesToHexString(mDigest.digest());
		} catch (NoSuchAlgorithmException e) {
			cacheKey = String.valueOf(key.hashCode());
		}
		return cacheKey;
	}
	private String bytesToHexString(byte[] bytes) {
		// http://stackoverflow.com/questions/332079
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < bytes.length; i++) {
			String hex = Integer.toHexString(0xFF & bytes[i]);
			if (hex.length() == 1) {
				sb.append('0');
			}
			sb.append(hex);
		}
		return sb.toString();
	}
}
